package com.itheima.ai.config;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
import co.elastic.clients.elasticsearch.indices.ExistsRequest;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.itheima.ai.utils.VectorDistanceUtils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.springframework.ai.embedding.EmbeddingModel;
import org.springframework.ai.reader.ExtractedTextFormatter;
import org.springframework.ai.reader.pdf.PagePdfDocumentReader;
import org.springframework.ai.reader.pdf.config.PdfDocumentReaderConfig;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.ai.vectorstore.elasticsearch.ElasticsearchVectorStore;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

@Configuration
public class AiFileConfig {

    // 常量定义
    private static final int EMBEDDING_DIMENSIONS = 4096;
    private static final String VECTOR_INDEX_NAME = "ai_document_index";
    // 配置参数注入
    @Value("${spring.ai.ollama.base-url}")
    private String ollamaBaseUrl;
    @Value("${spring.ai.ollama.embedding.model}")
    private String ollamaEmbeddingModelName;
    @Value("${spring.ai.vectorstore.elasticsearch.uris}")
    private String elasticsearchUri;
    @Value("${spring.ai.vectorstore.elasticsearch.username:}")
    private String elasticsearchUsername;
    @Value("${spring.ai.vectorstore.elasticsearch.password:}")
    private String elasticsearchPassword;
    @Value("${files.pdf.path}")
    private String pdfFilePath;

    // PDF读取器Bean
    @Bean
    public PagePdfDocumentReader pdfDocumentReader(ResourceLoader resourceLoader) {
        Resource pdfResource = resourceLoader.getResource("classpath:" + pdfFilePath);
        if (!pdfResource.exists()) {
            throw new IllegalArgumentException("PDF文件不存在：classpath:" + pdfFilePath);
        }

        PdfDocumentReaderConfig config = PdfDocumentReaderConfig.builder()
                .withPagesPerDocument(1)
                .withPageExtractedTextFormatter(ExtractedTextFormatter.defaults())
                .build();

        return new PagePdfDocumentReader(pdfResource, config);
    }

    // 核心Bean：Elasticsearch向量库
    @Bean("elasticsearchVectorStore")
    public VectorStore elasticsearchVectorStore(
            @Qualifier("ollamaEmbeddingModel") EmbeddingModel embeddingModel) {
        RestClient restClient = createEsRestClient();
        ElasticsearchTransport transport = new RestClientTransport(restClient, new JacksonJsonpMapper());
        ElasticsearchClient esClient = new ElasticsearchClient(transport);

        createEsIndexIfNotExists(esClient);
        return ElasticsearchVectorStore.builder(restClient, embeddingModel)
                .build();
    }

    // 初始化逻辑：配置类加载完成后自动执行（替代RagInitializer）
//    @Bean
//    public void initializePdfToVectorStore() {
//        try {
//            // 读取PDF文档
//            List<Document> documents = pdfDocumentReader.read();
//            System.out.println("成功读取PDF文件，共" + documents.size() + "页");
//            // 写入向量库
//            elasticsearchVectorStore.add(documents);
//            System.out.println("PDF内容已成功写入向量库");
//        } catch (Exception e) {
//            System.err.println("PDF初始化失败：" + e.getMessage());
//            e.printStackTrace();
//        }
//    }

    // 辅助方法：创建Elasticsearch客户端
    private RestClient createEsRestClient() {
        HttpHost httpHost = HttpHost.create(elasticsearchUri);
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();

        if (!elasticsearchUsername.isEmpty() && !elasticsearchPassword.isEmpty()) {
            credentialsProvider.setCredentials(
                    AuthScope.ANY,
                    new UsernamePasswordCredentials(elasticsearchUsername, elasticsearchPassword)
            );
        }

        return RestClient.builder(httpHost)
                .setHttpClientConfigCallback(httpClientBuilder ->
                        httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
                )
                .build();
    }

    // 辅助方法：创建索引
    private void createEsIndexIfNotExists(ElasticsearchClient esClient) {
        try {
            boolean indexExists = esClient.indices()
                    .exists(ExistsRequest.of(e -> e.index(VECTOR_INDEX_NAME)))
                    .value();

            if (!indexExists) {
                CreateIndexRequest request = CreateIndexRequest.of(c -> c
                        .index(VECTOR_INDEX_NAME)
                        .mappings(m -> m
                                .properties("embedding", p -> p
                                        .denseVector(dv -> dv
                                                .dims(EMBEDDING_DIMENSIONS)
                                                .index(true)
                                                .similarity("cosine")
                                        )
                                )
                                .properties("content", p -> p.text(t -> t))
                                .properties("metadata", p -> p.object(o -> o))
                        )
                );

                esClient.indices().create(request);
                System.out.println("创建索引成功：" + VECTOR_INDEX_NAME);
            }
        } catch (Exception e) {
            throw new RuntimeException("创建Elasticsearch索引失败", e);
        }
    }

    // 工具类Bean
    @Bean
    public VectorDistanceUtils vectorDistanceUtils() {
        return new VectorDistanceUtils();
    }
}
